/**
 * 
 */
package pt.xpand.xinx.entities;

import java.util.ArrayList;

import pt.xpand.xinx.utils.Constants;

/**
 * @author Kiko
 * 
 *         Class that creates and manages the board
 * 
 */
public class Board {

	private int size;
	private int dimension;

	ArrayList<ArrayList<ArrayList<String>>> board = null;

	public Board(int size, int dimension) {
		this.size = size;
		this.dimension = dimension;
		createBoard();
	}

	/**
	 * Creates the game board
	 */
	private void createBoard() {
		board = new ArrayList<ArrayList<ArrayList<String>>>();

		for (int i = 0; i < this.dimension; i++) {
			ArrayList<ArrayList<String>> dimension = new ArrayList<ArrayList<String>>();
			for (int k = 0; k < size; k++) {
				ArrayList<String> row = new ArrayList<String>();
				for (int j = 0; j < size; j++) {
					row.add(Constants.EMPTY_SPACE);
				}
				dimension.add(row);
			}
			board.add(dimension);
		}

	}

	public boolean isFull() {
		for (ArrayList<ArrayList<String>> dim : board) {
			for (ArrayList<String> row : dim) {
				for (String s : row) {
					if (s.equals(Constants.EMPTY_SPACE)) {
						return false;
					}
				}
			}
		}
		return true;
	}

	public String showPosition(Position pos, int dimension) {
		ArrayList<ArrayList<String>> dim = board.get(dimension);
		ArrayList<String> row = dim.get(pos.getY());
		String symbol = row.get(pos.getX());
		return symbol;
	}

	private void setPiece(Position pos, int dimension, String symbol) {
		ArrayList<ArrayList<String>> dim = board.get(dimension);
		ArrayList<String> row = dim.get(pos.getY());
		row.set(pos.getX(), symbol);
	}

	public boolean placePiece(Position position, String symbol) {
		for (int i = 0; i < dimension; i++) {
			if (showPosition(position, i).equals(Constants.EMPTY_SPACE)) {
				setPiece(position, i, symbol);
				return true;
			}
		}
		return false;
	}

	public void showBoard() {
		int dimension = 1;
		System.out.println("");
		System.out.println("Board State:");
		for (ArrayList<ArrayList<String>> dim : board) {
			System.out.println("");
			System.out.println("\tDimension: " + dimension);
			System.out.println("");
			System.out.print("\t");
			for (int i = 0; i < size * 2 + 1; i++) {
				System.out.print("-");
			}
			System.out.println("");
			for (ArrayList<String> row : dim) {
				System.out.print("\t|");
				for (String pos : row) {
					System.out.print(pos + "|");
				}
				System.out.println("");
				System.out.print("\t");
				for (int i = 0; i < size * 2 + 1; i++) {
					System.out.print("-");
				}
				System.out.println("");
			}
			dimension++;
		}
		System.out.println("");

	}

	public ArrayList<ArrayList<ArrayList<String>>> getBoard() {
		return board;
	}

	/**
	 * Checks if a given symbol has any winning situation
	 * 
	 * @param symbol
	 * @return
	 */
	
	//TODO: There are diagonals missing!!
	public boolean checkWinner(String symbol) {
		int finds = 0;
		for (ArrayList<ArrayList<String>> dim : board) {
			// check all rows
			for (ArrayList<String> row : dim) {
				for (String sym : row) {
					if (sym.equals(symbol)) {
						finds++;
					} else {
						finds = 0;
						break;
					}
				}
				if (finds == size) {
					return true;
				}
			}
			// check columns1
			for (int i = 0; i < size; i++) {
				for (ArrayList<String> row : dim) {

					if (row.get(i).equals(symbol)) {
						finds++;
					} else {
						finds = 0;
						break;
					}
				}

				if (finds == size) {
					return true;
				}
			}
			// check diagonals
			// From (0,0) to (x,x)
			int diagPos = 0;
			for (ArrayList<String> row : dim) {

				if (row.get(diagPos).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
				diagPos++;
			}
			if (finds == size) {
				return true;
			}

			// From (x,x) to (0,0)
			diagPos = size - 1;
			for (ArrayList<String> row : dim) {

				if (row.get(diagPos).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
				diagPos--;
			}
			if (finds == size) {
				return true;
			}

		}

		// only checks trough dimensions if the number of dimensions is the same
		// as the size. We can only have winning situations trough diferent
		// dimensions
		// if the board is a cube.
		if (size == dimension) {
			// all columns trough dimensions
			for (int i = 0; i < size; i++) {
				for (int j = 0; j < size; j++) {
					Position tempPos = new Position(i, j);
					for (int k = 0; k < size; k++) {
						if (showPosition(tempPos, k).equals(symbol)) {
							finds++;
						} else {
							finds = 0;
							break;
						}
					}

					if (finds == size) {
						return true;
					}
				}
			}

			// diagonals trough dimensions: 12 diagonals in all

			// START FROM (0,0,0)
			// (0,0,0) -> (0,y,z)
			for (int y = 0, z = 0; y < size; y++, z++) {
				Position c1 = new Position(0, y);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// (0,0,0) -> (x,0,z)
			for (int x = 0, z = 0; x < size; x++, z++) {
				Position c1 = new Position(x, 0);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// (0,0,0) -> (x,y,z)
			for (int x = 0, y = 0, z = 0; x < size; x++, y++, z++) {
				Position c1 = new Position(x, y);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// START FROM (0,y,0)
			// (0,y,0) -> (0,0,z)
			for (int y = size - 1, z = 0; z < size; y--, z++) {
				Position c1 = new Position(0, y);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// (0,y,0) -> (x,y,z)
			for (int x = 0, z = 0; x < size; x++, z++) {
				Position c1 = new Position(x, size - 1);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// (0,y,0) -> (x,0,z)
			for (int x = 0, y = size - 1, z = 0; x < size; x++, y--, z++) {
				Position c1 = new Position(x, y);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// START FROM (x,0,0)
			// (x,0,0) -> (0,0,z)
			for (int x = size - 1, z = 0; z < size; x--, z++) {
				Position c1 = new Position(x, 0);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// (x,0,0) -> (x,y,z)
			for (int y = 0, z = 0; y < size; y++, z++) {
				Position c1 = new Position(size - 1, y);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// (x,0,0) -> (0,y,z)
			for (int x = size - 1, y = 0, z = 0; y < size; x--, y++, z++) {
				Position c1 = new Position(x, y);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// START FROM (x,y,0)
			// (x,y,0) -> (x,0,z)
			for (int y = size - 1, z = 0; z < size; y--, z++) {
				Position c1 = new Position(size - 1, y);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// (x,y,0) -> (0,y,z)
			for (int x = 0, z = 0; z < size; x--, z++) {
				Position c1 = new Position(x, size - 1);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}

			// (x,y,0) -> (0,0,z)
			for (int x = size - 1, y = size - 1, z = 0; z < size; x--, y--, z++) {
				Position c1 = new Position(x, y);
				if (showPosition(c1, z).equals(symbol)) {
					finds++;
				} else {
					finds = 0;
					break;
				}
			}
			if (finds == size) {
				return true;
			}
		}

		// check trough dimensions
		return false;
	}

	public int getSize() {
		return size;
	}

	public void setSize(int size) {
		this.size = size;
	}

	public int getDimension() {
		return dimension;
	}

	public void setDimension(int dimension) {
		this.dimension = dimension;
	}

	/**
	 * @param position
	 */
	public boolean isValid(Position position) {
		if(position != null) {
			for (int i = 0; i < dimension; i++) {
				if (showPosition(position, i).equals(Constants.EMPTY_SPACE)) {
					return true;
				}
			}
		}
		return false;
	}

}
